﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace Calculator
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly List<string> formulas = new List<string>();
        private readonly List<string> results = new List<string>();
        private int formulasIndex;
        private int selectedIndex;
        private EState state = EState.Nothing;

        //ResourceDictionary resourceDictionary = new ResourceDictionary() { Source = new Uri("/Calculator;component/Dictionary1.xaml", UriKind.Relative) };
        private ArrayList statements;

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            String s = ((Button)sender).Content.ToString();

            switch (s)
            {
                case "=":
                    {
                        CalculateResult();
                        break;
                    }
                case "+/-":
                    {
                        break;
                    }
                case "C":
                    {
                        statements.Clear();
                        lstBox.Items.Refresh();
                        state = EState.Nothing;
                        break;
                    }
                case "<-":
                    {
                        break;
                    }
                default:
                    {
                        txtBoxEdit.Text += s;
                        break;
                    }
            }
        }

        private void CalculateResult()
        {
            try
            {
                var statement = new Statement { Assignment = txtBoxEdit.Text };

                if (statement.Assignment.Length > 0)
                {
                    var ev = new Eval();
                    string result = ev.Evaluate(statement.Assignment).ToString();
                    if (result.Length > 0)
                    {
                        state = EState.Result;
                        results.Add(result);
                        formulas.Add(statement.Result);
                        formulasIndex = formulas.Count - 1;

                        statement.Result = result;

                        statements.Add(statement);
                        lstBox.Items.MoveCurrentToLast();
                        lstBox.Items.Refresh();
                        selectedIndex++;
                    }
                    txtBoxEdit.Clear();
                }
            }
            catch (Exception ex)
            {
                txtBoxEdit.CaretIndex = ex.Message.Length;
            }
        }

        private void Grid_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            var s = ((Grid)sender);

            var buttons = new List<Button>();
            foreach (object item in numPad.Children)
            {
                if (item is Button)
                    buttons.Add((Button)item);
            }

            var map = new Dictionary<Key, string>
                          {
                              {Key.NumPad0, "0"},
                              {Key.NumPad1, "1"},
                              {Key.NumPad2, "2"},
                              {Key.NumPad3, "3"},
                              {Key.NumPad4, "4"},
                              {Key.NumPad5, "5"},
                              {Key.NumPad6, "6"},
                              {Key.NumPad7, "7"},
                              {Key.NumPad8, "8"},
                              {Key.NumPad9, "9"},
                              {Key.Add, "+"},
                              {Key.Subtract, "-"},
                              {Key.Multiply, "*"},
                              {Key.Divide, "/"},
                              {Key.Decimal, ","}
                          };

            if (map.ContainsKey(e.Key))
            {
                Button button = buttons.First(x => x.Content.ToString() == map[e.Key].ToString());
                button.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            statements = new ArrayList
                             {
                                 new Statement {Assignment = "1+2", Result = "3"},
                                 new Statement {Assignment = "2+2", Result = "4"},
                                 new Statement {Assignment = "2+sin(90)", Result = "3"},
                                 new Statement {Assignment = "1111111111111*22222222222222*333333333333333333*44444444444444444", Result = "3"}
                             };

            //lstBox.SetBinding(ListBox.ItemsSourceProperty, new Binding() { Source = statements, Mode = BindingMode.OneWay, IsAsync = false });
            lstBox.ItemsSource = statements;
            lstBox.UnselectAll();
        }

        private void txtBoxResult_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Up:
                    {
                        break;
                    }
                case Key.Down:
                    {
                        break;
                    }
                case Key.Left:
                    {
                        break;
                    }
                case Key.Right:
                    {
                        break;
                    }
                case Key.Enter:
                    {
                        CalculateResult();
                        e.Handled = true;
                        break;
                    }
            }
        }

        private void lstBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Enter:
                    {
                        string str = lstBox.SelectedValue.ToString();
                        txtBoxEdit.Text = str.LeftOf("=");
                        txtBoxEdit.CaretIndex = txtBoxEdit.Text.Length;
                        txtBoxEdit.Focus();
                        break;
                    }
                case Key.Escape:
                    {
                        txtBoxEdit.Focus();
                        break;
                    }
            }
        }

        private void lstBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.ExtentHeightChange > 0.0)
                ((ScrollViewer)e.OriginalSource).ScrollToEnd();
        }

        private void lstBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            string str = lstBox.SelectedValue.ToString();
            txtBoxEdit.Text = str.LeftOf("=");
        }

        private void txtBoxEdit_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Up:
                    {
                        if (lstBox.SelectedIndex == -1)
                            lstBox.SelectedItem = lstBox.Items[0];
                        else if (lstBox.SelectedIndex > 0)
                            lstBox.SelectedItem = lstBox.Items[lstBox.SelectedIndex - 1];

                        if (lstBox.SelectedIndex > 0)
                            lstBox.ScrollIntoView(lstBox.Items[lstBox.SelectedIndex - 1]);

                        txtBoxEdit.Text = lstBox.SelectedItem.ToString().LeftOf("=");
                        txtBoxEdit.CaretIndex = txtBoxEdit.Text.Length;
                        break;
                    }
                case Key.Down:
                    {
                        if (lstBox.SelectedIndex < 0)
                            lstBox.SelectedItem = lstBox.Items[0];
                        else if (lstBox.SelectedIndex < lstBox.Items.Count - 1)
                            lstBox.SelectedItem = lstBox.Items[lstBox.SelectedIndex + 1];

                        if (lstBox.SelectedIndex < lstBox.Items.Count - 1)
                            lstBox.ScrollIntoView(lstBox.Items[lstBox.SelectedIndex + 1]);

                        txtBoxEdit.Text = lstBox.SelectedItem.ToString().LeftOf("=");
                        txtBoxEdit.CaretIndex = txtBoxEdit.Text.Length;
                        break;
                    }
                case Key.Enter:
                    {
                        CalculateResult();
                        break;
                    }
            }
        }

        #region Nested type: EState

        private enum EState
        {
            Nothing = 0,
            Result,
            Modified
        }

        #endregion
    }
}